package com.glacier.yuyuan.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.glacier.common.core.constant.CommonConstant;
import com.glacier.common.core.domain.Result;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

/**
 * date 2023-01-14 20:10
 * security配置
 *
 * @author glacier
 * @version 1.0.0
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig {

    /**
     * 密码工具类
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 获取AuthenticationManager（认证管理器），登录时认证使用
     *
     * @param authenticationConfiguration
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    SecurityFilterChain commonHttp(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(authorize ->
                        authorize.requestMatchers("/favicon.ico",
                                        "/js/**",
                                        "/css/**",
                                        "/img/**",
                                        "/plugins/**",
                                        "/fonts/**",
                                        "/webjars/**",
                                        "/error"
                                )
                                .permitAll()
                                .anyRequest()
                                .authenticated()
                )
                .formLogin(formLogin -> {
                    formLogin.loginPage("/a/login")
                            .loginProcessingUrl("/a/login")
                            .permitAll()
                            .successHandler(authenticationSuccessHandler())
                            .failureHandler(failureHandler());
                })
                .logout(logout -> {
                    logout.logoutUrl("/a/logout")
                            .permitAll()
                            .invalidateHttpSession(true)
                            .clearAuthentication(true)
                            .deleteCookies("JSESSIONID")
                            .logoutSuccessHandler(logoutSuccessHandler());
                })
                .headers(headers -> {
                    headers.frameOptions()
                            .sameOrigin();
                });

        return http.build();
    }

    /**
     * 登录成功逻辑
     *
     * @return
     */
    private static AuthenticationSuccessHandler authenticationSuccessHandler() {
        return (request, response, authentication) -> {
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(CommonConstant.APPLICATION_JSON_CHARSET_UTF_8);
            response.setCharacterEncoding(CommonConstant.UTF8);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.registerModule(new JavaTimeModule());
            objectMapper.writeValue(response.getOutputStream(),
                    Result.ok("登录成功！", ""));
        };
    }

    /**
     * 登陆失败逻辑
     *
     * @return
     */
    private static AuthenticationFailureHandler failureHandler() {
        return (request, response, exception) -> {
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(CommonConstant.APPLICATION_JSON_CHARSET_UTF_8);
            response.setCharacterEncoding(CommonConstant.UTF8);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.registerModule(new JavaTimeModule());
            objectMapper.writeValue(response.getOutputStream(),
                    Result.fail(exception.getMessage()));
        };
    }

    /**
     * 退出成功逻辑
     *
     * @return
     */
    private static LogoutSuccessHandler logoutSuccessHandler() {
        return (request, response, authentication) -> {
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(CommonConstant.APPLICATION_JSON_CHARSET_UTF_8);
            response.setCharacterEncoding(CommonConstant.UTF8);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.registerModule(new JavaTimeModule());
            objectMapper.writeValue(response.getOutputStream(),
                    Result.ok("退出生成！", ""));
        };
    }
}
